import diff_match_patch as dmp_module
import pandas as pd
import openpyxl
from openpyxl.cell.text import InlineFont
from openpyxl.cell.rich_text import TextBlock, CellRichText
import warnings
import re
import os

# --- 基础函数 ---

def not_symbol_char_len(char):
    """返回去除符号和转义符号后的文本长度"""
    return len(re.sub(r'\W',"",char))

def compute_diff(text1, text2):
    """
    使用 diff_match_patch 计算差异，返回富文本段落和统计数据
    text1：原始文本（旧）
    text2：参考文本（新）
    text1对比text2，以text2为基准
    """
    # 差异对象
    dmp = dmp_module.diff_match_patch()
    diffs = dmp.diff_main(text1, text2)
    dmp.diff_cleanupSemantic(diffs)
    # 接受新旧文本的文本块列表
    old_segments = []
    new_segments = []
    # 初始化统计指标
    stats = {
        'total_chars': 0,
        'wrong_chars': 0,
        'extra_chars': 0,
        'missing_chars': 0
    }
    #差异分离：定义原始文本错字，漏字，多字
    i = 0
    while i < len(diffs):
        op, data = diffs[i]
        # 连续的删除和插入操作符为错字
        if i+1 < len(diffs) and op == dmp.DIFF_DELETE and diffs[i+1][0] == dmp.DIFF_INSERT:
            del_data = data
            ins_data = diffs[i+1][1]
            del_data_len=not_symbol_char_len(del_data)
            ins_data_len=not_symbol_char_len(ins_data)
            # 旧文本定义字体样式颜色、加粗
            font_del = InlineFont(color="FF0000", b=True,i=True,u='single')
            # 旧文本字体样式与文本绑定的文本块加入旧文本块列表
            old_segments.append(TextBlock(font_del, del_data))
            # 新文本定义字体样式颜色、加粗
            font_ins = InlineFont(color="0000ff", b=True,i=True)
            # 新文本字体样式与文本绑定的文本块加入新文本块列表
            new_segments.append(TextBlock(font_ins, ins_data))
            # 统计指标总字数与错字，符号不计入
            min_num=min(del_data_len,ins_data_len)
            max_num=max(del_data_len,ins_data_len)
            sup_num=max_num-min_num
            # 错字可能长度不一样
            # 如果删除操作符的文本长度大于替换操作符的文本长度，则会多字，多余的长度是sup_num
            if del_data_len > ins_data_len:
                stats['extra_chars'] += sup_num
            # 如果删除操作符的文本长度小于替换操作符的文本长度，则会缺字，缺少的长度是sup_num
            elif del_data_len < ins_data_len:
                stats['missing_chars'] += sup_num
            stats['wrong_chars'] += min_num
            stats['total_chars'] += ins_data_len
            i += 2#错字删除与插入操作符成对，跳过这两个
            continue
        #单独的删除操作符为多字
        if op == dmp.DIFF_DELETE:
            #serike:删除线
            font_del = InlineFont(color="9400D3", b=True,strike=True)
            old_segments.append(TextBlock(font_del, data))
            #统计指标多字，符号不计入
            stats['extra_chars'] += not_symbol_char_len(data)
        #单独的插入操作符为漏字
        elif op == dmp.DIFF_INSERT:
            font_ins = InlineFont(color="00AA00", b=True)
            new_segments.append(TextBlock(font_ins, data))
            #统计指标漏字，符号不计入
            stats['missing_chars'] += not_symbol_char_len(data)
            #统计指标总字数，符号不计入
            stats['total_chars'] += not_symbol_char_len(data)
        #原始文本和修改文本相匹配的部分
        else:
            old_segments.append(data)
            new_segments.append(data)
            #统计指标总字数，符号不计入
            stats['total_chars'] += not_symbol_char_len(data)
        i += 1
    error_num = stats['wrong_chars'] + stats['extra_chars'] + stats['missing_chars']#原始文本总错误字数
    # 计算错误率
    if stats['total_chars'] != 0:
        stats['error_rate'] = round(error_num / stats['total_chars'], 4)
        stats['acc_rate'] = 1-stats['error_rate']
    elif error_num == 0 and stats['total_chars'] == 0:
        stats['error_rate'] = 0
        stats['acc_rate'] = 0
    else:
        stats['error_rate'] = 1
        stats['acc_rate'] = 0
    return old_segments, new_segments, stats

def compare_texts(text1, text2):
    """对比两个文本，返回CellRichText对象和统计数据"""
    old_segments, new_segments, stats = compute_diff(text1, text2)
    #组合旧文本块列表的多个文本块为富文本
    old_rich = CellRichText(*old_segments)
    #组合新文本块列表的多个文本块为富文本
    new_rich = CellRichText(*new_segments)
    return old_rich, new_rich, stats

def write_to_excel(results, output_path):
    """把对比结果写入Excel,results是列表，嵌套元组。"""
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "对比结果"

    headers = ["转译文本（旧）", "参考文本（新）", "总字数", "错字数", "多字数", "缺字数", "错误率","字准率"]
    ws.append(headers)
    # 初始化汇总统计
    total_chars_sum = 0
    wrong_chars_sum = 0
    extra_chars_sum = 0
    missing_chars_sum = 0

    for idx, res in enumerate(results, start=2):
        old_rich, new_rich, stats = res

        ws[f"A{idx}"].value = old_rich
        ws[f"B{idx}"].value = new_rich
        ws[f"C{idx}"] = stats['total_chars']
        ws[f"D{idx}"] = stats['wrong_chars']
        ws[f"E{idx}"] = stats['extra_chars']
        ws[f"F{idx}"] = stats['missing_chars']
        ws[f"G{idx}"] = stats['error_rate']
        ws[f"H{idx}"] = stats['acc_rate']
        # 更新汇总
        total_chars_sum += stats['total_chars']
        wrong_chars_sum += stats['wrong_chars']
        extra_chars_sum += stats['extra_chars']
        missing_chars_sum += stats['missing_chars']
        # 写入汇总行
    summary_row = len(results) + 2
    ws[f"B{summary_row}"] = "汇总"
    ws[f"C{summary_row}"] = total_chars_sum
    ws[f"D{summary_row}"] = wrong_chars_sum
    ws[f"E{summary_row}"] = extra_chars_sum
    ws[f"F{summary_row}"] = missing_chars_sum

    # 汇总错误率单独算
    if total_chars_sum != 0:
        summary_error_rate= round(((wrong_chars_sum+extra_chars_sum+missing_chars_sum)/total_chars_sum),4)
        summary_acc_rate = 1-summary_error_rate
        ws[f"G{summary_row}"] = summary_error_rate
        ws[f"H{summary_row}"] = summary_acc_rate
        # 设置列宽
        ws.column_dimensions['A'].width = 60
        ws.column_dimensions['B'].width = 60
        for col in "CDEFG":
            ws.column_dimensions[col].width = 10
    wb.save(output_path)
    print(f"已保存到: {output_path}")

def log_exceptions(func):
    """捕获并打印异常的装饰器"""
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            print(f"[ERROR] {func.__name__}(): {str(e)}")
            return None  # 返回None表示处理失败
    return wrapper
@log_exceptions
def process_single_row(raw_text1, raw_text2, increase_regex=False, regex_pattern=None):
    """excel行处理函数（含正则提取逻辑）默认不使用正则处理行数据，行数据格式需要一样。"""

    if increase_regex:
        if regex_pattern:
            try:
                text1 = re.findall(regex_pattern, raw_text1)[0].strip()
                text2 = re.findall(regex_pattern, raw_text2)[0].strip()
                return text1, text2
            except Exception as e:
                print(f"正则匹配过程中出现错误: {e}")
                print(f"无法从文本中提取内容：{raw_text1}, {raw_text2}")
                return None
        else:
            raise ValueError("increase_regex is set to 'True', but regex_pattern is None. regex_pattern should not be None.")
    else:
        if increase_regex == False and regex_pattern is not None:
            warning_msg='警告：regex_pattern is not None,but increase_re = False,将忽略regex_pattern直接比较初始文本。'
            warnings.warn(warning_msg, UserWarning)
            return raw_text1,raw_text2
        return raw_text1, raw_text2
# --- 批量处理函数 ---

def batch_compare_from_excel(input_path, output_path, increase_regex=False, regex_pattern=None):
    """从Excel批量读取文本，生成对比结果"""
    if not os.path.exists(input_path):
        raise FileNotFoundError(f"找不到文件: {input_path}")
    df = pd.read_excel(input_path)
    # 填充缺失值为空字符串
    df=df.fillna('')
    results = []
    for i in range(len(df)):
        text1 = df.iloc[i:i+1,0].values[0]
        text2 = df.iloc[i:i+1,1].values[0]
        processed = process_single_row(text1, text2, increase_regex, regex_pattern)
        # 跳过正则处理错误的行
        if processed is None:
            print(f"文件{input_path} 第 {i + 2} 行处理失败，已跳过")
            continue
        new_text1, new_text2 = processed
        # 跳过没有内容的行
        if len(new_text1) ==0 and len(new_text2) ==0:
            continue
        result = compare_texts(new_text1,new_text2)
        # result是元组类型
        if result is not None:
            results.append(result)
    if input_path != output_path:
        write_to_excel(results, output_path)
    else:
        raise ValueError('导出文件路径与读取文件路径重复，可能会导致覆盖文件!请重新输入文件路径。')
# --- 示例使用 ---

if __name__ == "__main__":
    pass
    # 单条文本测试
    # text1 = "文缺字，多了错字情况了。"
    # text2 = "文本缺字，多错字情况。"
    # write_to_excel([compare_texts(text1, text2)], "single_diff.xlsx")

    # 批量读取Excel测试
    batch_compare_from_excel("test_data/广州训练50轮.xlsx", "match_result/广州训练50轮对比结果.xlsx",increase_regex=True,regex_pattern=r'\|([^|]*)$')